#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern.h"

int fflag;
char *fnombre;

static void uso(void);

main(int argc, char *argv[]) {
	struct stat sb;
	FILE *fp;
	off_t off;
	enum ESTILO estilo;
	int ch;
	char *p;

	/*
	 * Las opciones de "final" son algo "especiales".  En primer lugar, -n 10
	 * significa lo mismo que -n -10 y no -n +10.  En segundo lugar,
	 * las opciones numericas parten de 1 (no son desplazamientos),
	 * por lo que -n +1 se refiere a la primera linea,
	 * y -c -1 se refiere al ultimo byte.
	 */
#define	ARG(unidades, adelante, atras) { \
	if (estilo) \
		uso(); \
	off = strtol(optarg, &p, 10) * (unidades); \
	if (*p) \
		err("offset ilegal-- %s", optarg); \
	switch(optarg[0]) { \
	case '+': \
		if (off) \
			off -= (unidades-1); \
			estilo = (adelante); \
		break; \
	case '-': \
		off = -off; \
		/* FALLTHROUGH */ \
	default: \
		estilo = (atras); \
		break; \
	} \
}

	estilo = NOTSET;
	while ((ch = getopt(argc, argv, "b:c:n:f")) != EOF)
		switch(ch) {
		case 'b':
			ARG(512, FBYTES, RBYTES);
			break;
		case 'c':
			ARG(1, FBYTES, RBYTES);
			break;
		case 'f':
			fflag = 1;
			break;
		case 'n':
			ARG(1, FLINEAS, RLINEAS);
			break;
		case '?':
		default:
			uso();
		}
	argc -= optind;
	argv += optind;

	/*
	 * Si no se especifica estilo, el valor por omision son las 10 ultimas lineas
	 */
	if (estilo == NOTSET) {
		off = 10;
		estilo = RLINEAS;
	}

	if (fnombre = *argv) {
		if ((fp = fopen(fnombre, "r")) == NULL)
			ierr();
	} else {
		fp = stdin;
		fnombre = "stdin";
	}

	if (fstat(fileno(fp), &sb))
		ierr();

	/*
	 * Determinar si la entrada es un pipe, en cuyo caso no admite la opcion -f
	 */
	if (lseek(fileno(fp), 0L, SEEK_CUR) == -1 && errno == ESPIPE) {
		errno = 0;
		fflag = 0;
	}

	adelante(fp, estilo, off, &sb);
	exit(0);
}

static void
uso()
{
	(void)fprintf(stderr,
	    "uso: final [-f] [-b # | -c # | -n #] [fichero]\n");
	exit(1);
}
